package com.varian.rabbit.config;

import cn.hutool.extra.spring.SpringUtil;
import com.varian.rabbit.interceptor.RabbitListenerInterceptor;
import com.varian.rabbit.util.RabbitUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitTemplateConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

import static com.varian.rabbit.constant.RabbitConstant.ROUTE_DEAD;

/**
 * @author ben
 * @since 2024/8/29
 */
@Slf4j
@AutoConfiguration
public class RabbitAutoConfig {

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public ConnectionNameStrategy connectionNameStrategy() {
        return connectionFactory -> SpringUtil.getApplicationName();
    }

    @Bean
    public RabbitListenerInterceptor rabbitListenerInterceptor(SimpleRabbitListenerContainerFactory factory) {
        RabbitListenerInterceptor interceptor = new RabbitListenerInterceptor();
        factory.setAdviceChain(interceptor);
        return interceptor;
    }

    @Bean
    public MessageRecoverer republisher(RabbitTemplate rabbitTemplate) {
        return new RepublishMessageRecoverer(rabbitTemplate, ROUTE_DEAD.exchange(), ROUTE_DEAD.routingKey());
    }

    @Bean
    public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer rabbitTemplateConfigurer, ConnectionFactory connectionFactory, MessageConverter messageConverter) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplateConfigurer.configure(rabbitTemplate, connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter);
        rabbitTemplate.setRetryTemplate(retryTemplate());
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> log.info("confirm callback: correlationData: {}, ack: {}, cause: {}", correlationData, ack, cause));
        rabbitTemplate.setReturnsCallback(returnedMessage -> log.info("return callback: {}", returnedMessage));
        RabbitUtil.setRabbitTemplate(rabbitTemplate);
        log.info("initialed RabbitTemplate And RabbitUtil.");
        return rabbitTemplate;
    }

    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // 重试间隔时间
        backOffPolicy.setBackOffPeriod(5000);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        // 最大重试次数
        retryPolicy.setMaxAttempts(3);
        retryTemplate.setRetryPolicy(retryPolicy);
        return retryTemplate;
    }

}
